﻿#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>//function和bind被定义在此头文件内
using namespace std;

//学习lambda表达式所用代码

//class Fruit
//{
//public:
//	string _name;
//	double _price;
//	Fruit(const string& s = "", double price = 1)
//		:_name(s)
//		, _price(price)
//	{
//
//	}
//};
//void Print(vector<Fruit> v)
//{
//	for (auto& e : v)
//	{
//		cout << e._name << "->" << e._price << endl;
//	}
//	cout << endl;
//}
//
//int x = 10;//全局变量不能也不用捕捉，直接可以使用
//
////lambda表达式如果定义在全局域中，捕捉列表必须为空
//auto test = []
//{
//	cout << "test" << endl;
//};
//
//int main()
//{
//	static int tmp = 8;//static局部变量不能也不用捕捉，可以直接使用
//
//	////一个简单的lambda表达式
//	//auto add = [](int x, int y) {return x + y; };
//	//cout << add(1, 2) << endl;
//	//cout << "---------------------------------------------------" << endl;
//	//
//	//vector<Fruit> v = { {"xigua", 1}, {"taozi", 5}, {"juzi", 4} };
//	//sort(v.begin(), v.end(), [](const Fruit& f1, const Fruit& f2)->bool {return f1._price < f2._price; });
//	//Print(v);
//	//cout << "---------------------------------------------------" << endl;
//	//
//	//sort(v.begin(), v.end(), [](const Fruit& f1, const Fruit& f2)->bool {return f1._name < f2._name; });
//	//Print(v);
//	//cout << "---------------------------------------------------" << endl;
//
//	////lambda表达式本质是一个匿名函数对象
//	//auto func = [] {cout << "hello world!" << endl; };
//	//func();
//	//cout << "---------------------------------------------------" << endl;
//
//	//传值捕捉(lambda内不能修改传值捕捉过来的变量)
//	int a = 1, b = 2;
//	auto add1 = [a, b](int c) 
//	{
//		//a++;//不能修改
//		return a + b + c; 
//	};
//	cout << add1(3) << endl;
//	cout << "---------------------------------------------------" << endl;
//
//	//传值捕捉(在参数列表加mutable修饰，就可修改传值捕捉
//	// 过来的变量，使用该修饰后，参数列表即使为空也不可省略)
//	auto add2 = [a, b](int c)mutable
//	{
//		a++; b++;//可以修改，但是不会影响外部a、b变量
//		return a + b + c;
//	};
//	cout << add2(3) << endl;
//	cout << "a = " << a << ',' << "b = " << b << endl;
//	cout << "---------------------------------------------------" << endl;
//
//	//传引用捕捉(可以修改传引用捕捉过来的变量，且会影响外部a、b变量)
//	auto add3 = [&a, &b](int c) 
//	{
//		a++; b++;//可以修改，会影响外部a、b变量
//		return a + b + c + tmp;
//	};
//	cout << add3(3) << endl;
//	cout << "a = " << a << ',' << "b = " << b << endl;
//	cout << "---------------------------------------------------" << endl;
//
//	//隐式捕捉(分为隐式传值捕捉、隐式传引用捕捉)
//	//隐式传值捕捉
//	auto add4 = [=] {return x + a; };
//	cout << add4() << endl;
//	//隐式传引用捕捉
//	auto add5 = [&] {return x + a; };
//	cout << add5() << endl;
//	cout << "---------------------------------------------------" << endl;
//
//	//混合捕捉
//	int i = 519, j = 1314, k = 258;
//	//i是传引用捕捉，其他变量为传值捕捉
//	auto add6 = [=, &i]
//	{
//		//j++;//传值捕捉不可修改
//		i++;//传引用捕捉可以修改，且影响外部
//		return i + j + k;
//	};
//	cout << add6() << endl;
//	//i是传值捕捉，其他变量为传引用捕捉
//	auto add7 = [&, i]
//	{
//		return i + j + k;
//	};
//	cout << add7() << endl;
//	cout << "---------------------------------------------------" << endl;
//
//	return 0;
//}


//学习包装器function所用代码
//int f(int a, int b)
//{
//	return a + b;
//}
//struct Functor
//{
//public:
//	int operator() (int a, int b)
//	{
//		return a + b;
//	}
//};
//class Plus
//{
//public:
//	Plus(int n = 10)
//		:_n(n)
//	{}
//	static int plusi(int a, int b)
//	{
//		return a + b;
//	}
//	double plusd(double a, double b)
//	{
//		return (a + b) * _n;
//	}
//private:
//	int _n;
//};
//int main()
//{
//	//包装各种可调用对象
//	
//	//包装函数指针（函数指针是可调用对象的一种）
//	function<int(int, int)> f1 = f;
//	cout << f1(1, 1) << endl;
//
//	//包装仿函数对象
//	function<int(int, int)> f2 = Functor();
//	cout << f2(1, 1) << endl;
//
//	//包装lambda表达式
//	function<int(int, int)> f3 = [](int a, int b) -> int	
//	{
//		return a + b;
//	};
//	cout << f3(1, 1) << endl;
//
//	//包装静态成员函数(指针)
//	//成员函数要指定类域且前面要加&才能获取地址(静态成员函数可不加&)
//	function<int(int, int)> f4 = &Plus::plusi;
//	function<int(int, int)> f5 = Plus::plusi;
//	cout << f4(1, 1) << "  " << f5(1, 1) << endl;
//
//	//包装成员函数(指针)
//	//普通成员函数还有⼀个隐含的this指针参数，所以绑定时传对象、对象引用、对象的指针过去都可以
//	function<double(Plus,double, double)> f6 = &Plus::plusd;
//	cout << f6(Plus(), 1.1, 2.2) << endl;
//
//	Plus p;
//	function<double(Plus&, double, double)> f7 = &Plus::plusd;
//	cout << f7(p, 1.1, 2.2) << endl;
//
//	function<double(Plus&&, double, double)> f8 = &Plus::plusd;
//	cout << f8(move(p), 1.1, 2.2) << endl;
//
//	function<double(Plus*, double, double)> f9 = &Plus::plusd;
//	cout << f9(&p, 1.1, 2.2) << endl;
//
//
//	return 0;
//}

//学习包装器bind所用代码
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
	return (a - b) * 10;
}
class Plus
{
public:
	static int plusi(int a, int b)
	{
		return a - b;
	}
	double plusd(double a, double b)
	{
		return a + b;
	}
};
int main()
{
	//bind是一个函数模板，第一个参数接收一个可调用对象，
	//处理后返回一个仿函数对象

	//_1代表第一个实参、_2代表第二个实参……
	auto sub1 = bind(Sub, _1, _2);
	function<int(int, int)> sub2 = bind(Sub, _1, _2);
	cout << sub1(10, 5) << endl;
	cout << sub2(10, 5) << endl;
	cout << "-------------------------------------------------------" << endl;

	//bind可以调整参数顺序
	auto sub3 = bind(&Plus::plusi, _1, _2);
	auto sub4 = bind(&Plus::plusi, _2, _1);
	cout << sub3(1, 5) << endl;
	cout << sub4(1, 5) << endl;
	cout << "-------------------------------------------------------" << endl;


	//bind可以调整参数个数
	auto sub5 = bind(Sub, 100, _1);
	function<int(int)> sub6 = bind(Sub, 100, _1);//与sub5等价
	cout << sub5(50) << endl;
	cout << sub6(50) << endl;
	cout << "-------------------------------------------------------" << endl;


	auto sub7 = bind(&Plus::plusi, 100, 20);
	function<int()> sub8 = bind(&Plus::plusi, 100, 20);//与sub7等价
	cout << sub7() << endl;
	cout << sub8() << endl;
	cout << "-------------------------------------------------------" << endl;

	function<double(Plus, double, double)> sub9 = &Plus::plusd;
	cout << sub9(Plus(), 10, 20) << endl;//每次都要传Plus对象，不方便
	//就可以用bind调整参数个数
	function<double(double, double)> sub10 = bind(&Plus::plusd, Plus(), _1, _2);
	auto sub11 = bind(&Plus::plusd, Plus(), _1, _2);//与sub10等价
	cout << sub10(10, 20) << endl;
	cout << sub11(10, 20) << endl;
	cout << "-------------------------------------------------------" << endl;

	return 0;
}